iT邦幫忙

2025 iThome 鐵人賽

DAY 6
0

VII.IG實戰

26 TWPAS Bundle

對,我偷改題目拉,今天來貼一個參考的範例

實際上有很多東西要改,但這個範例應該可以讓各位了解怎麼樣構建出一個Mapping,

輸入的內容都是自定義的,只是給各位參考,
如果照著範例來做應該可以得到一個跟範例Bundle-bun-1.json完全相同的內容結果。

在實作的時候推薦大家先採用最小原則,
意指先將必填的欄位完成,再來檢視有什麼非必填的欄位是需要提供的資訊再行補上。

#FUME

(
	$serverURL := "https://test.com.tw/fhir/"; //提供fullUrl存取用
	$loinc := "http://loinc.org"; // Loinc代碼uri
	$sct := "http://snomed.info/sct"; // Snomed代碼uri
	$ucum := "http://unitsofmeasure.org"; // Ucum代碼uri
	
	$wrap := function($input) {
	  "<div xmlns=\"http://www.w3.org/1999/xhtml\">" & $input & "</div>"
	}; //讓輸入綁成xhtml的樣子,因為沒有html的欄位驗證器會跳Warning
	

	$entries := (
	
		[
			$claim, 
			$encounter, 
			$patient, 
			$practitioner, 
			$organization, 
			$organizationGen, 
			$diagnosticReportImage, 
			$imageStudy, 
			$media, 
			$observationCancerStage, 
			$diagnosticReport, 
			$observationDiagnostic, 
			$specimen, 
			$documentReference, 
			$observationLaboratoryResult, 
			$observationPatientAssessment, 
			$medicationRequestTreat, 
			$procedure, 
			$substance, 
			$observationTreatmentAssessment, 
			$medicationRequestApply, 
			$coverage, 
			$claimResponse, 
			$organizationOrg
		]; //Bundle下轄資源總覽
  
	);
	
	InstanceOf: Bundle
	  * id = bundle_id
	  * meta
		* profile = "https://nhicore.nhi.gov.tw/pas/StructureDefinition/Bundle-twpas"
	  * type = 'collection'
	  * timestamp = $now() //時間戳,可以把這一欄改成輸入指定值,去輸入調整。

	  * ($entries).entry 
		* resource = $ 
		* fullUrl = $serverURL & resourceType & ($exists(id) ? '/' & id : '' ) //整理fullUrl的格式表示法
)

#INPUT

{
	"bundle_id" : "TWPAS",
}

這是最初始的模板,定義好了Bundle中需要的內容,還有$entries的集成欄位,
$entries前有三個Terminology Alias的原因是因為,
如果讀者採用的是stateless的環境,這些ConceptMap中的Alias都無法被FUME讀取,
所以在這裡重新定義一次,不會影響到運作。

接下來把每個物件與輸入項對應即可:
$claim是整個TWPAS中最麻煩的部分,我們先跳過等最後面再來處理,
這邊的Resource排列基本上是照著Bundle-bun-1.json的安排來做的,讀者可以配著這個範例來閱讀本文。

先來整理其他的Resource:

Encounter : 1..1

#FUME

$encounter :=
(
    InstanceOf: Encounter   
    * id = encounter_id
    * meta
      * profile = "https://nhicore.nhi.gov.tw/pas/StructureDefinition/Encounter-twpas"
    * text
      * status =  "generated"
      * div = ($exists(encounter_HTML) ? encounter_HTML : $wrap(encounter_id))
    * status = "planned" 
    * class
      * system = "http://terminology.hl7.org/CodeSystem/v3-ActCode"
      * code = "AMB"
    * serviceType
      * coding
        * system = "https://twcore.mohw.gov.tw/ig/twcore/CodeSystem/medical-consultation-department-nhi-tw"
        * code = encounter_serviceType_code
);

#INPUT

{
  "encounter_id" : "enc-min",
  "encounter_HTML" : "<div xmlns=\"http://www.w3.org/1999/xhtml\">enc-min</div>",
  "encounter_serviceType_code" : "AJ",
}

這裡提供了encounter_HTML,所以在FUME裡面的text.div中,
根據判斷式選擇會使用encounter_HTML,而不會呼叫$wrap(encounter_id)
請注意text.div中只接受xHTML的格式,這個欄位原則上是提供人閱讀的,但要利用JSONata來組裝html不太方便,
因為是非必填的欄位,筆者不太喜歡特別處理這個欄位。

可以看到$encounter的內容很簡單,在大多數的CodeSystem都是綁定一種的情況下,就是一個一個去對應即可。
這個輸入其實也就只包含了:

  1. 就醫科別
  2. Encounter的類型(門診)

Patient : 1..1

#FUME

$patient := 
(
    InstanceOf: Patient
    * id = patient_id
    * meta
      * profile = "https://nhicore.nhi.gov.tw/pas/StructureDefinition/Patient-twpas"
    * text
      * status =  "generated"
      * div = ($exists(patient_HTML) ? patient_HTML : $wrap(patient_id))
    * identifier
      * use = "official"
      * type
        * coding
          * system = "http://terminology.hl7.org/CodeSystem/v2-0203"
          * code = "NNxxx"
      * system = "http://www.moi.gov.tw"
      * value = patient_identifier_idCardNumber_value
    * identifier
      * use = ($exists(patient_identifier_medicalRecord_value) ? "official")
      * type
        * coding
          * system = ($exists(patient_identifier_medicalRecord_value) ? "http://terminology.hl7.org/CodeSystem/v2-0203")
          * code = ($exists(patient_identifier_medicalRecord_value) ? "MR")
      * system = patient_identifier_medicalRecord_system
      * value = patient_identifier_medicalRecord_value
    * name
      * use = "usual"
      * text = patient_name
    * gender = patient_gender
    * birthDate = patient_birthDate
);

#INPUT

{
	"patient_id" : "pat-min",
    "patient_HTML" : "<div xmlns=\"http://www.w3.org/1999/xhtml\">pat-min</div>",
    "patient_identifier_idCardNumber_value" : "A123456789",
    "patient_identifier_medicalRecord_system" : "https://tpech.gov.taipei",
    "patient_identifier_medicalRecord_value" : "123456",
    "patient_name" : "王大明",
    "patient_gender" : "male",
    "patient_birthDate" : "2000-01-01",
}

Patient也是相對簡單,從範例中的欄位可以看到需要填入的也就只有六項資訊:

  1. 身分證字號
  2. 病歷號
  3. 病患姓名
  4. 病患性別
  5. 病患生日

Practitioner : 1..*

#FUME

$practitioner := (practitioners).(
    InstanceOf: Practitioner

    * id = practitioner_id
    * meta
      * profile = "https://nhicore.nhi.gov.tw/pas/StructureDefinition/Practitioner-twpas"
    * text
      * status =  "generated"
      * div = ($exists(practitioner_HTML) ? practitioner_HTML : $wrap(practitioner_id))
    * identifier
      * use = "official"
      * type
        * coding
          * system = "http://terminology.hl7.org/CodeSystem/v2-0203"
          * code = "NNxxx"
      * system = "http://www.moi.gov.tw"
      * value = practitioner_idCardNumber_value 
    * identifier
      * use = ($exists(practitioner_medicalLicense_value) ? "official")
      * type
        * coding
          * system = ($exists(practitioner_medicalLicense_value) ? "http://terminology.hl7.org/CodeSystem/v2-0203")
          * code = ($exists(practitioner_medicalLicense_value) ? "MD")
      * system = ($exists(practitioner_medicalLicense_value) ? "https://dep.mohw.gov.tw/DOMA")
      * value = ($exists(practitioner_medicalLicense_value) ? practitioner_medicalLicense_value)  
);

#INPUT

{
	"practitioners": [
	{
	  "practitioner_id" : "pra-min",
	  "practitioner_HTML" : "<div xmlns=\"http://www.w3.org/1999/xhtml\">pra-min-00</div>",
	  "practitioner_idCardNumber_value" : "E123456789",
	  "practitioner_medicalLicense_value" : "A123456"
	}
  ],
}

Practitioner是醫事人員的Resource,從Cardinality中可以看到他在Bundle Profile中的限制是1..*

也就是說雖然必填,但可以不只一個,事實上一個療程中包含了檢查、診斷、手術與用藥,這之中必然不只有一名醫事人員介入,
因為這項Resource支援多人的關係,所以要在外層執行一個嵌套,把單個醫事人員的資訊包裹於其中。

而Practitioner的資訊也很簡單,

  1. 身分證字號
  2. 醫事人員證號

可以觀察一下FUME的欄位,在identifier中,由於身分證字號(NNxxx)是必填;而醫事人員證號(MD)卻不是,
在第二個identifier的設計上,我們就必須要把醫事人員證號的輸入值practitioner_medicalLicense_value視為key,
當該值不存在的時候,整個identifier的內容都應該清空,所以設計上所有identifier內的值填入都應該以證號的有無為準。

Organization : 1..1

#FUME

$organization :=
(
    InstanceOf: Organization
    * id = organization_id
    * meta
      * profile = "https://nhicore.nhi.gov.tw/pas/StructureDefinition/Organization-twpas"
    * text
      * status =  "generated"
      * div = ($exists(organization_HTML) ? organization_HTML : $wrap(organization_id))
    * identifier
      * use = "official"
      * type
        * coding
          * system = "http://terminology.hl7.org/CodeSystem/v2-0203"
          * code = "PRN"
      * system = "https://nhicore.nhi.gov.tw/pas/CodeSystem/organization-identifier-tw"
      * value = organization_value
    * type
      * coding
        * system = "http://terminology.hl7.org/CodeSystem/organization-type"
        * code = "prov"
    * name = organization_name
);

#INPUT

{
  "organization_id" : "org-hosp-example",
  "organization_HTML" : "<div xmlns=\"http://www.w3.org/1999/xhtml\">org-min</div>",
  "organization_value" : "0101090517",
  "organization_name" : "臺北市立聯合醫院",
}

醫事機構的內容也很簡單:
1.醫事機構代號
2.醫事機構名稱

這兩個值原則上是綁在一起的,所以事實上可以透過$resolve來完成其中一邊的數據。

OrganizationGen : 0..1

#FUME

$organizationGen := (organizationGen).(

    InstanceOf: Organization
    * id = organizationGen_id
    * meta
      * profile = "https://nhicore.nhi.gov.tw/pas/StructureDefinition/Organization-genetic-testing-twpas"
    * text
      * status =  "generated"
      * div = ($exists(organizationGen_HTML) ? organizationGen_HTML : $wrap(organizationGen_id))
    * identifier
      * use = "official"
      * type
        * coding
          * system = "http://terminology.hl7.org/CodeSystem/v2-0203"
          * code = "PRN"
      * system = ($exists(organizationGen_value) ? "https://dep.mohw.gov.tw")
      * value = organizationGen_value
    * type
      * coding
        * system = "http://terminology.hl7.org/CodeSystem/organization-type"
        * code = "prov"
    * name = organizationGen_name
);

#INPUT

{
	"organizationGen": [
	{
	  "organizationGen_id" : "org-gen-min",
	  "organizationGen_HTML" : "<div xmlns=\"http://www.w3.org/1999/xhtml\">org-gen-min</div>",
	  "organizationGen_value" : "TAF",
	  "organizationGen_name" : "測試基因機構"
	}
  ],
}

Organization與OrganizationGen兩個都同樣是Organization Resource,
唯一的差別在使用的Profile不同,不同的Profile造就了Resource不同的樣貌與用途。

要注意到OrganizationGen,基因檢查機構,這個Resource在規定上是非必填的,
在實務上並不是每個病患都有機會或能力執行基因篩檢,因此既然沒有執行基因檢測,也就不會有這些子Resource的內容。

這個Resource的內部定義其實也有些模稜兩可,畢竟除了organizationGen_name作為名稱識別外,
organizationGen_value可填入的值可以是機構類型或是案號,無法充分表達這個值-機構代碼的唯一性。

DiagnosticReportImage : 0..1

#FUME

$diagnosticReportImage := (diagnosticReportImages).(
    InstanceOf: DiagnosticReport
    * id = diagnosticReportImage_id
    * meta
      * profile = "https://nhicore.nhi.gov.tw/pas/StructureDefinition/DiagnosticReport-image-twpas"
    * text
      * status =  "generated"
      * div = ($exists(diagnosticReportImage_HTML) ? diagnosticReportImage_HTML : $wrap(diagnosticReportImage_id))
    * status = diagnosticReportImage_status
    * category
      * coding
        * system = "https://nhicore.nhi.gov.tw/pas/CodeSystem/nhi-supporting-info-type"
        * code = "imagingReport"
    * code
      * coding
        * system = $contains(diagnosticReportImage_code, "-") ? $loinc : "https://twcore.mohw.gov.tw/ig/twcore/CodeSystem/icd-10-pcs-2023-tw"
        * code = diagnosticReportImage_code
    * subject
      * reference = ($exists($pat_id) ? 'Patient/' & $pat_id)
    * effectiveDateTime = diagnosticReportImage_effectiveDateTime
    * performer
      * reference = ($exists(diagnosticReportImage_performer) ? 'Practitioner/' & diagnosticReportImage_performer)
    * imagingStudy
      * reference = ($exists(diagnosticReportImage_imagingStudy) ? 'ImagingStudy/' & diagnosticReportImage_imagingStudy)
    * media
      * link
        * reference = ($exists(diagnosticReportImage_media) ? 'Media/' & diagnosticReportImage_media)
    * conclusion = diagnosticReportImage_conclusion
    * (diagnosticReportImage_file).presentedForm
      * contentType = ($exists(diagnosticReportImage_fileType) ? diagnosticReportImage_fileType : 'application/pdf')
      * url = diagnosticReportImage_fileURL
      * title = diagnosticReportImage_fileTitle
);

#INPUT

{
	"diagnosticReportImages" : [
	{
	  "diagnosticReportImage_id" : "diaRep-ima-min",
	  "diagnosticReportImage_HTML" : "<div xmlns=\"http://www.w3.org/1999/xhtml\">diaRep-ima-min</div>",
	  "diagnosticReportImage_status" : "final",
	  "diagnosticReportImage_code" : "B34JZZ3",
	  "diagnosticReportImage_effectiveDateTime" : "2024-05-07",
	  "diagnosticReportImage_performer" : "pra-min",
	  "diagnosticReportImage_imagingStudy" : "imaStu-min",
	  "diagnosticReportImage_media" : "med-min",
	  "diagnosticReportImage_conclusion" : "影像報告結果",
	  "diagnosticReportImage_file" : [
		{
		  
		  "diagnosticReportImage_fileURL" : "file://test01.pdf",
		  "diagnosticReportImage_fileTitle" : "影像報告"
		},
		{
		  "diagnosticReportImage_fileType" : "application/pdf",
		  "diagnosticReportImage_fileURL" : "file://test02.pdf",
		  "diagnosticReportImage_fileTitle" : "影像報告"
		}
	  ]
    }
	],
}

影像報告,從這裡開始情況變得複雜,首先這個Resource的Cardinality是0..1,
並且這個影像報告下含了ImageStudy與Media兩個Resource,

另外一個隱性的問題是某些reference_id在物件的外面,在這裡diagnosticReportImages的subject.reference找不到patient_id,
解決方法就是將他變數化放在$entries中:

#FUME
$pat_id := patient_id;
$orgGen_id := (organizationGen).($exists(organizationGen_id) ? organizationGen_id);

會發生這樣子的問題通常都是數量上限為1的Resource,其實要規避這個問題也是很簡單,
就是把patient等Resource也用物件的形式包起來,如:

#INPUT

"patients" : [
{
	"patient_id" : "pat-min",
    "patient_HTML" : "<div xmlns=\"http://www.w3.org/1999/xhtml\">pat-min</div>",
    "patient_identifier_idCardNumber_value" : "A123456789",
    "patient_identifier_medicalRecord_system" : "https://tpech.gov.taipei",
    "patient_identifier_medicalRecord_value" : "123456",
    "patient_name" : "王大明",
    "patient_gender" : "male",
    "patient_birthDate" : "2000-01-01",
}
]

這樣的形式會統一些,但是這給了使用者輸入上能輸入多個的風險,看讀者怎麼取捨。
反過來說,因為容許複數個的Resource,實際在使用的時候FUME不會知道該選擇哪一個給引用,
所以這就是必須要留下來給輸入填入的欄位了,如Practitioner,
除此之外,為了簡化輸入,如果沒有填入diagnosticReportImage_fileType的值,讓他預設為application/pdf

在diagnosticReportImage中我們還缺少了ImageStudy與Media這兩個下轄Resource,接著來實作他。

imageStudy : 0..*

#FUME

$imageStudy := (imagingStudies).(

    InstanceOf: ImagingStudy
    * id = imagingStudy_id
    * meta
      * profile = "https://nhicore.nhi.gov.tw/pas/StructureDefinition/ImagingStudy-twpas"
    * text
      * status =  "generated"
      * div = ($exists(imagingStudy_HTML) ? imagingStudy_HTML : $wrap(imagingStudy_id))
    * identifier
      * system = ($exists(imagingStudy_studyUID) ? "urn:dicom:uid")
      * value = imagingStudy_studyUID
    * status = imagingStudy_status
    * subject
      * reference = ($exists($pat_id) ? 'Patient/' & $pat_id)
    * (imagingStudy_series).series
      * uid = imagingStudy_seriesUID
      * modality
        * system = ($exists(imagingStudy_seriesModality) ? "http://dicom.nema.org/resources/ontology/DCM")
        * code = imagingStudy_seriesModality
      * bodySite
        * system = ($exists(imagingStudy_seriesBodySite_code) ? $sct)
        * code = imagingStudy_seriesBodySite_code
        * display = imagingStudy_seriesBodySite_display
      * (imagingStudy_seriesInstances).instance
        * uid = imagingStudy_seriesInstances_uid
        * sopClass
          * system = ($exists(imagingStudy_seriesInstances_sopClass_code) ? "urn:ietf:rfc:3986")
          * code = imagingStudy_seriesInstances_sopClass_code
);

#INPUT

{
	"imagingStudies" : [
	{
	  "imagingStudy_id" : "imaStu-min",
	  "imagingStudy_HTML" : "<div xmlns=\"http://www.w3.org/1999/xhtml\">imaStu-min</div>",
	  "imagingStudy_studyUID" : "urn:oid:2.16.886.2102.54.4546465747.465465465",
	  "imagingStudy_status" : "registered",
	  "imagingStudy_series" : [
		{
		  "imagingStudy_seriesUID" : "2.16.886.2102.54.4546465747.465465466",
		  "imagingStudy_seriesModality" : "CT",
		  "imagingStudy_seriesBodySite_code" : "774007",
		  "imagingStudy_seriesBodySite_display" : "Structure of head and/or neck",
		  "imagingStudy_seriesInstances" : [
			{
			  "imagingStudy_seriesInstances_uid" : "2.25.88017001449189502323411118737039844241",
			  "imagingStudy_seriesInstances_sopClass_code" : "urn:oid:1.2.840.10008.5.1.4.1.1.2"
			}
		  ]
		},
		{
		  "imagingStudy_seriesUID" : "2.16.876.2102.54.4546465747.465465466",
		  "imagingStudy_seriesModality" : "CT",
		  "imagingStudy_seriesBodySite_code" : "774007",
		  "imagingStudy_seriesBodySite_display" : "Structure of head and/or neck"
		}
	  ]
	}
  ],
}

DICOM影像也非常的麻煩,前面的部分提到過,DICOM影像要透過各種方式讀取出他的各個ID來填入,
Study -> Series -> Instance,幸運的是Instance本身是非必填,畢竟一張一張影像填入實在是太折磨人了。

Media : 0..*

#FUME

$media := (media).(

    InstanceOf: Media
    * id = media_id
    * meta
      * profile = "https://nhicore.nhi.gov.tw/pas/StructureDefinition/Media-twpas"
    * text
      * status =  "generated"
      * div = ($exists(media_HTML) ? media_HTML : $wrap(media_id))
    * status = media_status
    * subject
      * reference = ($exists($pat_id) ? 'Patient/' & $pat_id)
    * bodySite
      * coding
        * system = ($exists(media_bodySite_code) ? $sct)
        * code = media_bodySite_code 
        * display = media_bodySite_display  
    * (media_content).content
      * contentType = media_content_contentType
      * url = media_content_url
);

#INPUT

{
	"media" : [
	{
	  "media_id" : "med-min",
	  "media_HTML" : "<div xmlns=\"http://www.w3.org/1999/xhtml\">med-min</div>",
	  "media_status" : "completed",
	  "media_bodySite_code" : "774007",
	  "media_bodySite_display" : "Structure of head and/or neck",
	  "media_content" : [
		{
		  "media_content_contentType" : "image/jpeg",
		  "media_content_url" : "file://US01.jpg"
		}
	  ]
	}
  ],
}

非DICOM影像可以塞入其他媒體,這個就比較單純些。

再來是Observation,這個Resource構成了整個IG中相對重要的部分。

observationCancerStage : 0..*

#FUME

$observationCancerStage_main := (observationCancerStages).(

    InstanceOf: Observation
    * id = observationCancerStage_id
    * meta
      * profile = "https://nhicore.nhi.gov.tw/pas/StructureDefinition/Observation-cancer-stage-twpas"
    * text
      * status =  "generated"
      * div = ($exists(observationCancerStage_HTML) ? observationCancerStage_HTML : $wrap(observationCancerStage_id))
    * status = observationCancerStage_status
    * category
      * coding
        * system = "https://nhicore.nhi.gov.tw/pas/CodeSystem/nhi-supporting-info-type"
        * code = "cancerStage"
    * code
      * coding
        * system = $startsWith(observationCancerStage_code_code, 'C') ? "https://nhicore.nhi.gov.tw/pas/CodeSystem/nci-thesaurus" : $sct
        * code = observationCancerStage_code_code
    * subject
      * reference = ($exists($pat_id) ? 'Patient/' & $pat_id)
    * effectiveDateTime = observationCancerStage_effectiveDateTime
    * performer
      * reference = ($exists(observationCancerStage_performer) ? 'Practitioner/' & observationCancerStage_performer)
);

$observationCancerStage_code := (observationCancerStages).(

      InstanceOf: Observation
      * valueCodeableConcept
        * coding
          * system = "https://nhicore.nhi.gov.tw/pas/CodeSystem/nci-thesaurus"
          * code = observationCancerStage_value
);

$observationCancerStage_str := (observationCancerStages).(

      InstanceOf: Observation
      * valueString = observationCancerStage_value
);

$observationCancerStage_int := (observationCancerStages).(

        InstanceOf: Observation
        * valueInteger = $type(observationCancerStage_value) = "number" ? observationCancerStage_value : -1
);

$observationCancerStage := (observationCancerStages).(
  (observationCancerStage_value in $nci_thesaurus) ? $merge([$observationCancerStage_main,$observationCancerStage_code]) : 
  $type(observationCancerStage_value) = "number" ? $merge([$observationCancerStage_main,$observationCancerStage_int]) :
  $merge([$observationCancerStage_main,$observationCancerStage_str])
  
);

#INPUT

{
	"observationCancerStages" : [
	{
	  "observationCancerStage_id" : "obs-cancer-figo",
	  "observationCancerStage_HTML" : "<div xmlns=\"http://www.w3.org/1999/xhtml\">obs-cancer-figo</div>",
	  "observationCancerStage_status" : "final",
	  "observationCancerStage_code_code" : "385361009",
	  "observationCancerStage_effectiveDateTime" : "2024-05-07",
	  "observationCancerStage_performer" : "pra-min",
	  "observationCancerStage_value" : "C96244"
	}
  ],
}

這邊寫成這樣是為了處理value[x]的問題,在TWPAS的設計中,因為value[x]在這裡可以有多種形態填入,
但只能選擇一種,這就產生了問題,我要讓value[x]能夠自動判斷型別來輸出對應的轉換結果,

可是在這個例子中,valueString/valueCodeableConcept/valueInteger是互斥的,其永遠只能輸出最下方的有效內容,

為了解決這個問題,筆者在這裡把value[x]的部分分別獨立成三個物件,藉由$merge的方式來接合符合對應的型態value[x]

$nci_thesaurus是https://nhicore.nhi.gov.tw/pas/CodeSystem/nci-thesaurus的內容,
為了不要使用$resolve(stateless設計),筆者在考量值集不大的情況下將整個值集以物件方式嵌入FUME Mapping中

#FUME

$nci_thesaurus := (
	  [
		"C96243",
		"C96244",
		...
	  ]
	);
	

在這個範例中,observationCancerStage_value的值為C96244,因為這個值在$nci_thesaurus內,
所以會自動使用$observationCancerStage_code組合成$observationCancerStage。

前面的已經講解滿多的了,後面就是應用這些內容把他填滿即可

DiagnosticReport : 0..*

#FUME

$diagnosticReport := (diagnosticReports).(

    InstanceOf: DiagnosticReport
    * id = diagnosticReport_id
    * meta
      * profile = "https://nhicore.nhi.gov.tw/pas/StructureDefinition/DiagnosticReport-twpas"
    * text
      * status =  "generated"
      * div = ($exists(diagnosticReport_HTML) ? diagnosticReport_HTML : $wrap(diagnosticReport_id))
    * status = "final"
    * category
      * coding
        * system = "https://nhicore.nhi.gov.tw/pas/CodeSystem/nhi-supporting-info-type"
        * code = "examinationReport"
    * code
      * coding
        * system = ($exists(diagnosticReport_code_code) ? $loinc)
        * code = diagnosticReport_code_code
      * text = (($exists(diagnosticReport_code_text)) ? diagnosticReport_code_text)

    * subject
      * reference = ($exists($pat_id) ? 'Patient/' & $pat_id)
    * effectiveDateTime = diagnosticReport_effectiveDateTime
    * performer
      * reference = ($exists(diagnosticReport_performer) ? 'Practitioner/' & diagnosticReport_performer)
    * specimen
      * reference = ($exists(diagnosticReport_specimen) ? 'Specimen/' & diagnosticReport_specimen)
    * conclusion = diagnosticReport_conclusion
    * (diagnosticReport_file).presentedForm
      * contentType = ($exists(diagnosticReport_fileType) ? diagnosticReport_fileType : 'application/pdf')
      * url = diagnosticReport_fileURL
      * title = diagnosticReport_fileTitle
);

#INPUT

{
	"diagnosticReports" : [
	{
	  "diagnosticReport_id" : "diaRep-min",
	  "diagnosticReport_HTML" : "<div xmlns=\"http://www.w3.org/1999/xhtml\">diaRep-min</div>",
	  "diagnosticReport_code_code" : "66117-3",
	  "diagnosticReport_code_text" : "66117-3",
	  "diagnosticReport_effectiveDateTime" : "2024-05-07",
	  "diagnosticReport_performer" : "pra-min",
	  "diagnosticReport_specimen" : "spe-min",
	  "diagnosticReport_conclusion" : "細胞檢查報告結果",
	  "diagnosticReport_file" : [
		{
		  "diagnosticReport_fileType" : "application/pdf",
		  "diagnosticReport_fileURL" : "file://Dptest01.pdf",
		  "diagnosticReport_fileTitle" : "dp_test01.pdf"
		},
		{
		  "diagnosticReport_fileType" : "application/pdf",
		  "diagnosticReport_fileURL" : "file://Dptest02.pdf",
		  "diagnosticReport_fileTitle" : "dp_test02.pdf"
		}
	  ]
	}
  ],
}

看了一下篇幅已經有夠多了,剩下的部分就交給讀者完成吧,
主要會產生差異的都是在想辦法減少輸入端的負擔,
明天我們來講一下claim要怎麼做,因為claim是最難處理的,
實作的時候請務必要看著IG的StructureDefinition來進行,很多時候實作完的結果是會產生validation error的,


上一篇
[FUME TO FHIR] 25 TWPAS/TWCI 實戰簡介,思路分析
下一篇
[FUME TO FHIR] 27 撰寫FUME,組合resource成Bundle
系列文
30天FUME TO FHIR轉換實戰 - 從入門到燃燒殆盡30
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言